﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Data;
using System.Diagnostics;
using System.Windows.Input;
using NodeControl;
using System.Threading.Tasks;

namespace PracaInz_v0
{    
    class CreatePoint
    {
        public Ellipse r = new Ellipse();           // punkt
        RadialGradientBrush rgb;                    // wypelnienie
        public static double pixels = 7;            // rozmiar punktu

        public DataRow dr;                          // dane punktu 

        public double X = 0;                        // wsp punktu
        public double Y = 0;

        public double parX = 0;                     // wspolrzedne przodka
        public double parY = 0;

        public bool lastP = false;                  // czy punkt jest ostatnim wezlem
        public Cluster cl;                          // jezeli lastPoint == true wtedy stworz obiekt Cluster
        public DataTable LogicRule = new DataTable();

        DrawTree _DT;

        string _vectsource;

        public CreatePoint(DrawTree DT, string vectsource)
        {
            _vectsource = vectsource;
            _DT = DT;
            LogicRule.Columns.Add("Attribute", typeof(int));         // kolumna z numerem atrybutu
            LogicRule.Columns.Add("Sign", typeof(char));             // kolumna ze znakiem podziału
            LogicRule.Columns.Add("Value", typeof(double));          // kolumna z wartoscia podzialu
            r.MouseEnter += Ellipse_MouseEnter;
        }

        RadialGradientBrush rColor()
        {
            RadialGradientBrush c;
            if (Convert.ToInt32(dr[1]) % 2 == 1)
                c = new RadialGradientBrush(Colors.Gold, Colors.Silver);
            else
                c = new RadialGradientBrush(Colors.Gold, Colors.Salmon);
            return c;
        }

        public Ellipse createPoint(double top, double px)     //rysuje na srodku           //px to wspolrzedna x przodka
        {
            rgb = rColor();
            r.Width = pixels;
            r.Height = pixels;
            rgb.GradientOrigin = new Point(0.25, 0.25);
            r.Fill = rgb;

            Canvas.SetTop(r, top - (pixels / 2));
            Canvas.SetLeft(r, px - (pixels / 2));
            parX = px;
            parY = top - _DT.pdistH;

            X = px;
            Y = top;

            line(parX, X, parY, Y);

            return r;
        }

        public Ellipse createPointL(double top, double px, double left)     // rysuje po lewej stronie
        {
            if (left < 4)       // jezeli przesuniecie mniejsze od 4 to ustawiamy na 4 do przemyslenia
                left = 4;

            rgb = rColor();
            r.Width = pixels;
            r.Height = pixels;
            rgb.GradientOrigin = new Point(0.25, 0.25);
            r.Fill = rgb;

            Canvas.SetTop(r, top - (pixels / 2));
            Canvas.SetLeft(r, px - left - (pixels / 2));
            parX = px;
            parY = top - _DT.pdistH;

            X = px - left;
            Y = top;

            line(parX, X, parY, Y);

            return r;
        }

        public Ellipse createPointR(double top, double px, double left)             // rysuje po prawej 
        {
            if (left < 4)       // jezeli przesuniecie mniejsze od 4 to ustawiamy na 4 do przemyslenia
                left = 4;

            rgb = rColor();
            r.Width = pixels;
            r.Height = pixels;
            rgb.GradientOrigin = new Point(0.25, 0.25);
            r.Fill = rgb;

            Canvas.SetTop(r, top - (pixels / 2));
            Canvas.SetLeft(r, px + left - (pixels / 2));
            parX = px;
            parY = top - _DT.pdistH;

            X = px + left;
            Y = top;

            line(parX, X, parY, Y);

            return r;
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        void line(double x1, double x2, double y1, double y2)   // bedzie rysowac linie łączące punkty
        {
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext context = geometry.Open())
            {
                double theta = Math.Atan2(y1 - y2, x1 - x2);
                double sint = Math.Sin(theta);
                double cost = Math.Cos(theta);

                Point pt1 = new Point(x1, y1);
                Point pt2 = new Point(x2, y2);

                double odcinek = Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));

                //odleglosc strzalki od 2 punktu
                double n = 7;
                double m = odcinek - n;
                double XN = ((m * x2) + (n * x1)) / odcinek;
                double YN = ((m * y2) + (n * y1)) / odcinek;
                double HeadWidth = 5;
                double HeadHeight = 2.5;

                Point pt3 = new Point(XN, YN);

                Point pt4 = new Point(
                    XN + (HeadWidth * cost - HeadHeight * sint),
                    YN + (HeadWidth * sint + HeadHeight * cost));

                Point pt5 = new Point(
                    XN + (HeadWidth * cost + HeadHeight * sint),
                    YN - (HeadHeight * cost - HeadWidth * sint));

                context.BeginFigure(pt1, true, true);
                context.LineTo(pt2, true, true);
                context.LineTo(pt3, true, true);
                context.LineTo(pt4, true, true);
                context.LineTo(pt5, true, true);
                context.LineTo(pt3, true, true);
            }
            geometry.Freeze();

            Path arrow = new Path();
            arrow.Data = geometry;
            arrow.Fill = System.Windows.Media.Brushes.YellowGreen;
            arrow.Stroke = new SolidColorBrush(Colors.YellowGreen);
            arrow.StrokeThickness = 1;
            Canvas.SetZIndex(arrow, -10);

            if (Convert.ToInt32(dr[0]) != 1)
                _DT.TreeCanvas.Children.Add(arrow);
        }
       
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        async void Ellipse_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {          
            Node node = new Node(this.dr, (Ellipse)sender, this._DT.TreeCanvas.Width);
            node.MouseLeave += Node_MouseLeave;

            if (this._DT._TVS.ShowClusters && this.lastP)
            {
                node.NodeColorIn = Colors.Green;
                node.NodeColorOut = Colors.SteelBlue;
                node.NodeMean = cl.NewMean;
                node.NodeNumVect = cl.ClusterVectCount;

                this._DT._TVS.RegresionFormula = this.cl.RegFormula;
            }
            
            this._DT.TreeCanvas.Children.Add(node);

            await Task.Run(() =>
                {
                    this._DT._TVS.GlobalNodeNum = this.dr[0].ToString();
                    this._DT._TVS.NodeLevel = this.dr[1].ToString();
                    this._DT._TVS.NodeNum = this.dr[2].ToString();

                    if (this._DT._TVS.ShowNodeVectors)                                                   // pokazuje vektory w datagrid
                    {
                        if (this._DT._TVS.ShowClusters && this.lastP)                                   // wyswietla wektory znajdujace sie w klastrze
                        {
                            this._DT._TVS.DataView = MergeTables(LoadData.loadFileVect(this._vectsource), this.cl.AdditionalVect);
                        }
                        else                                                                 // wyswietla wektory w wezle               
                        {
                            this._DT._TVS.DataView = LoadData.loadFileVect(this._vectsource).DefaultView;
                        }
                    }
                    else if (this._DT._TVS.ShowLogicRules)                            // pokazuje regule w datagrid
                    {
                        if (this._DT._TVS.ShowClusters && this.lastP)                                   // wyswietla zoptymalizowane regoly logiczne~dla ostatniego wezla-klastra
                        {
                            this._DT._TVS.DataView = this.cl.SLR.DefaultView;
                        }
                        else                                                                    // wyswietla regoly logiczne
                        {
                            this._DT._TVS.DataView = this.LogicRule.DefaultView;
                        }
                    }
                });           
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        void Node_MouseLeave(object sender, MouseEventArgs e)
        {
            Node n = sender as Node;
            this._DT.TreeCanvas.Children.Remove(n);
            this._DT._TVS.GlobalNodeNum = "";
            this._DT._TVS.NodeLevel = "";
            this._DT._TVS.NodeNum = "";
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public static DataView MergeTables(DataTable dt1, DataTable dt2)
        {
            return dt1.AsEnumerable().Union(dt2.AsEnumerable()).CopyToDataTable().DefaultView;
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }
}
